package xj.graph2d.app.prop;

import static xj.app.BaseApplicationFrame.getResourceString;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import xj.meta.StereotypeManager;
import xj.model.uml.NamedElement;

public class StereotypeField extends ModelPropertyField {

  public StereotypeField() {
  }

  public StereotypeField(JFrame owner) {
    super(getResourceString("Stereotypes.text"));
    JButton editButton = makeEditButton(getResourceString("Stereotypes.edit.text"));
    editButton.setToolTipText(getResourceString("Stereotypes.edit.tip"));

    stereotypeDialog = new StereotypeDialog(owner, 
					    getResourceString("Stereotypes.dialog.title"), 
					    this);
    editButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
	updateEditorValue();
	stereotypeDialog.showDialog();
      }
    });
    setEditor(editButton);
  }

  @Override
  protected void updateTips() {
    if (editor != null) {
      String prefix = "<html><body bgcolor='white'><b>Stereotypes</b><br>&nbsp;&nbsp";
      String suffix = "</body></html>";
      String text = null; 
      if (model != null) {
	Set<String> st = model.getStereotypes();
	if (st != null && st.size() > 0) {
	  StringBuilder sb = new StringBuilder("\u00AB");
	  Iterator<String> iter = st.iterator();
	  boolean first = true;
	  while (iter.hasNext()) {
	    if (first) {
	      first = false;
	    } else {
	      sb.append(", ");
	    }
	    sb.append(iter.next());
	  }
	  sb.append("\u00BB");
	  text = sb.toString();
	}
      }
      if (text == null) { 
	text = "<i>none</i>";
      }
      editor.setToolTipText(prefix + text + suffix);      
    }
  }

  @Override
  public void updateEditorValue() {
    if (model != null) {
      Set<String> st = model.getStereotypes();

      StereotypeManager stManager = StereotypeManager.getInstance();
      String tempName = model.getClass().getName();
      Set<String> available = stManager.getAvailableStereotypes(tempName);
      if (available == null && shape != null) {
	tempName = shape.getTemplateName();
	available = stManager.getAvailableStereotypes(tempName);
      }

      if (false) {
	System.out.println("StereotypeField.updateEditorValue(): tempName="
			   + tempName + " available=" + available);
      }

      stereotypePanel.setStereotypes(available, st);
    }

    if (stereotypeDialog != null) {
      String name = null;
      String element = null;
      if (model instanceof NamedElement) {
	name = ((NamedElement) model).getName();
      }
      if (name == null || name.length() == 0) {
	name = "<unnamed>";
      }
      element = "[" + model.getElementName() + "]";

      stereotypeDialog.setTopTitle("Steteotypes of", name, element);
    }
  }

  @Override
  public void updateModelValue() {
    if (model != null) {
      Set<String> st = stereotypePanel.getStereotypes();
      model.setStereotypes(st);

      updateTips();
    }
  }

  protected StereotypeDialog stereotypeDialog;

  protected StereotypePanel stereotypePanel;
}

class StereotypeDialog extends JDialog implements ActionListener {

  public StereotypeDialog(JFrame owner, String title, StereotypeField field) {
    super(owner, title, true);
    setAlwaysOnTop(true);
    this.field = field;

    JPanel topPanel = new JPanel(); 
    add(topPanel); 
    topPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 5, 10));
    topPanel.setLayout(new BorderLayout());

    stereotypePanel = new StereotypePanel(field);
    topPanel.add(stereotypePanel, BorderLayout.CENTER);

    titleLabel = new TitleComponent();
    titleLabel.setNameStyle(Font.ITALIC);
    titleLabel.setNameColor(new Color(0, 0, 128));
    titleLabel.setElementColor(new Color(0, 128, 0));
    topPanel.add(titleLabel, BorderLayout.NORTH);

    JPanel buttonPanel = new JPanel();
    buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0));
    buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
    cancelButton = new JButton("Cancel");
    cancelButton.addActionListener(this);
    buttonPanel.add(cancelButton);
    okButton = new JButton("Ok");
    okButton.addActionListener(this);
    buttonPanel.add(okButton);
    topPanel.add(buttonPanel, BorderLayout.SOUTH);

    setSize(500, 300);
  }

  public void setTopTitle(String prefix, String name, String element) {
    if (stereotypePanel != null &&
	titleLabel != null) { 
      stereotypePanel.setBorder(BorderFactory.createEtchedBorder());
      titleLabel.setTitle(prefix, name, element);
    }
  }

  /*
   * public Set<String> getStereotypes() { if (topPanel != null) { return
   * topPanel.getStereotypes(); } return null; }
   * 
   * public void setStereotypes(Set<String> available, Set<String> st) {
   * if (topPanel != null) { topPanel.setStereotypes(available, st); } }
   */
  public void showDialog() {
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension dialogSize = getSize();
    setLocation(screenSize.width / 2 - dialogSize.width / 2, 
		screenSize.height / 2 - dialogSize.height / 2);
    setVisible(true);
  }

  public void actionPerformed(ActionEvent e) {
    Object source = e.getSource();
    if (source == okButton) {
      if (field != null) {
	field.updateModelValue();
	field.updateShape();
      }
      setVisible(false);
    } else if (source == cancelButton) {
      setVisible(false);
    }
  }

  protected StereotypeField field;

  protected StereotypePanel stereotypePanel;

  protected JButton okButton, cancelButton, addButton;

  protected TitleComponent titleLabel;

}

class StereotypePanel 
  extends JPanel 
  implements ListSelectionListener, ActionListener {

  StereotypePanel(StereotypeField field) {
    if (field != null) {
      field.stereotypePanel = this;
    }

    setLayout(new BorderLayout());

    topPanel = new JPanel();
    GridBagLayout gbl = new GridBagLayout();
    // topPanel.setBackground(Color.white);
    topPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 5, 10));
    topPanel.setLayout(gbl);

    JLabel label1 = new JLabel("Availabel Stereotypes");
    JLabel label2 = new JLabel("Selected Stereotypes");
    JLabel label3 = new JLabel();
    addComp(label1, topPanel, gbl, 0, 0, 1, 1, 1.0, 0);
    addComp(label2, topPanel, gbl, 2, 0, 1, 1, 1.0, 0);
    addComp(label3, topPanel, gbl, 1, 0, 1, 1, 1.0, 0);

    leftList = new JList(new DefaultListModel());
    leftList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    JScrollPane leftScrollPane = new JScrollPane(leftList);
    leftList.addListSelectionListener(this);
    addComp(leftScrollPane, topPanel, gbl, 0, 1, 1, 5, 1.0, 1.0);

    rightList = new JList(new DefaultListModel());
    rightList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    JScrollPane rightScrollPane = new JScrollPane(rightList);
    rightList.addListSelectionListener(this);
    addComp(rightScrollPane, topPanel, gbl, 2, 1, 1, 5, 1.0, 1.0);

    toRightButton = new JButton(">");
    toRightButton.setActionCommand("toRight");
    toRightButton.addActionListener(this);
    addComp(toRightButton, topPanel, gbl, 1, 1, 1, 1, 0, 0);
    allToRightButton = new JButton(">>");
    allToRightButton.setActionCommand("allToRight");
    allToRightButton.addActionListener(this);
    addComp(allToRightButton, topPanel, gbl, 1, 2, 1, 1, 0, 0);
    toLeftButton = new JButton("<");
    toLeftButton.setActionCommand("toLeft");
    toLeftButton.addActionListener(this);
    addComp(toLeftButton, topPanel, gbl, 1, 3, 1, 1, 0, 0);
    allToLeftButton = new JButton("<<");
    allToLeftButton.setActionCommand("allToLeft");
    allToLeftButton.addActionListener(this);
    addComp(allToLeftButton, topPanel, gbl, 1, 4, 1, 1, 0, 0);

    add(topPanel, BorderLayout.CENTER);

    bottomPanel = new JPanel();
    bottomPanel.setLayout(new FlowLayout());
    bottomPanel.add(new JLabel("New stereotype"));
    newStereotypeField = new JTextField(10);
    bottomPanel.add(newStereotypeField);
    addButton1 = new JButton("Available");
    addButton1.addActionListener(this);
    bottomPanel.add(addButton1);
    addButton2 = new JButton("Selected");
    addButton2.addActionListener(this);
    bottomPanel.add(addButton2);

    add(bottomPanel, BorderLayout.SOUTH);
  }

  protected void addComp(JComponent comp, JPanel parent, GridBagLayout gbl,
      int x, int y, int w, int h, double weightx, double weighty) {
    if (comp != null && parent != null && gbl != null) {
      GridBagConstraints c = new GridBagConstraints();
      c.fill = GridBagConstraints.BOTH;
      c.gridx = x;
      c.gridy = y;
      c.gridwidth = w;
      c.gridheight = h;
      c.weightx = weightx;
      c.weighty = weighty;
      parent.add(comp);
      gbl.setConstraints(comp, c);
    }
  }

  protected void move(JList fromList, JList toList, boolean all) {
    if (fromList != null && toList != null) {
      DefaultListModel fromModel = (DefaultListModel) fromList.getModel();
      DefaultListModel toModel = (DefaultListModel) toList.getModel();
      if (all) {
	int n = fromModel.getSize();
	for (int i = 0; i < n; i++) {
	  toModel.addElement(fromModel.getElementAt(i));
	}
	fromModel.clear();
      } else {
	Object[] items = fromList.getSelectedValues();
	int[] indices = fromList.getSelectedIndices();
	toList.clearSelection();
	fromList.clearSelection();
	int n = items.length;
	for (int i = 0; i < n; i++) {
	  toModel.addElement(items[i]);
	  int m = toModel.getSize() - 1;
	  toList.setSelectedIndex(m);
	  if (i == 0) {
	    toList.ensureIndexIsVisible(m);
	  }
	}
	for (int j = n - 1; j >= 0; j--) {
	  fromModel.removeElementAt(indices[j]);
	}
      }
    }
  }

  public Set<String> getStereotypes() {
    Set<String> s = new HashSet();
    DefaultListModel rightModel = (DefaultListModel) rightList.getModel();
    int n = rightModel.getSize();
    for (int i = 0; i < n; i++) {
      s.add((String) rightModel.getElementAt(i));
    }
    return s;
  }

  public void setStereotypes(Set<String> available, Set<String> st) {
    DefaultListModel rightModel = (DefaultListModel) rightList.getModel();
    DefaultListModel leftModel = (DefaultListModel) leftList.getModel();
    rightModel.clear();
    leftModel.clear();
    if (available != null) {
      Iterator<String> iter = available.iterator();
      while (iter.hasNext()) {
	String s = iter.next();
	if (!st.contains(s)) {
	  leftModel.addElement(s);
	}
      }
    }
    if (st != null) {
      Iterator<String> iter = st.iterator();
      while (iter.hasNext()) {
	rightModel.addElement(iter.next());
      }
    }
  }

  public void valueChanged(ListSelectionEvent e) {
    if (e.getValueIsAdjusting() == false) {

    }
  }

  public void actionPerformed(ActionEvent e) {
    Object source = e.getSource();
    String st = newStereotypeField.getText();
    if (st != null) {
      st = st.trim();
    }
    if (source == addButton1) {
      if (st != null && st.length() > 0) {
	DefaultListModel leftModel = (DefaultListModel) leftList.getModel();
	leftModel.addElement(st);
      }
      newStereotypeField.setText(null);
    } else if (source == addButton2) {
      if (st != null && st.length() > 0) {
	DefaultListModel rightModel = (DefaultListModel) rightList.getModel();
	rightModel.addElement(st);
      }
      newStereotypeField.setText(null);
    } else if (source instanceof JButton) {
      JButton btn = (JButton) source;
      String cmd = btn.getActionCommand();
      if ("toRight".equals(cmd)) {
	move(leftList, rightList, false);
      } else if ("allToRight".equals(cmd)) {
	move(leftList, rightList, true);
      } else if ("toLeft".equals(cmd)) {
	move(rightList, leftList, false);
      } else if ("allToLeft".equals(cmd)) {
	move(rightList, leftList, true);
      }
    }
  }

  protected JPanel topPanel;

  protected JPanel bottomPanel;

  protected JTextField newStereotypeField;

  protected JButton addButton1, addButton2;

  protected JList leftList, rightList;

  protected JButton toLeftButton, allToLeftButton, toRightButton,
      allToRightButton;

}
